package cn.kivensoft.xlsx.reader;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class Sheet {
	//private static final String NS_MAIN = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
	private String name;
	private String path;
	private String id;
	private boolean hidden;
	private Workbook workbook;
	private List<Row> rows = new ArrayList<Row>();
	private List<Column> columns = new ArrayList<Column>();

	public Sheet(String name) {
		this.name = name;
	}

	public Sheet(String name, String id, boolean hidden) {
		this.name = name;
		this.id = id;
		this.hidden = hidden;
	}

	public String getName() {
		return name;
	}

	public void setName(String value) {
		name = value;
	}

	public String getId() {
		return id;
	}

	public void setId(String value) {
		id = value;
	}

	public String getPath() {
		return path;
	}

	public void setPath(String value) {
		path = value;
	}

	public boolean getHidden() {
		return hidden;
	}

	public void setHidden(boolean value) {
		hidden = value;
	}

	public Workbook getWorkbook() {
		return workbook;
	}

	public void setWorkbook(Workbook value) {
		workbook = value;
	}

	public Row row(int index) {
		return index >= rows.size() ? null : rows.get(index);
	}

	public Column column(int index) {
		return index >= columns.size() ? null : columns.get(index);
	}

	public Cell getCell(int rowIndex, int columnIndex) {
		if (rowIndex < rows.size()) {
			Row r = rows.get(rowIndex);
			return r == null ? null : r.getCell(columnIndex);
		} else if (columnIndex < columns.size()) {
			Column c = columns.get(columnIndex);
			return c == null ? null : c.getCell(rowIndex);
		} else
			return null;
	}

	public Cell getCell(String name) throws Exception {
		return getCell(getRowIndex(name), getColumnIndex(name));
	}

	public List<Row> getRows() {
		return rows;
	}

	public List<Column> getColumns() {
		return columns;
	}

	public void open(byte[] bytes) throws Exception {
		InputStream is = Workbook.readZipEntryContent(bytes, getPath());
		if (is == null) throw new IOException("Can't find " + getPath() + ".");
		
		SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
		parser.parse(is, new DefaultHandler() {
			private boolean find_sheetData = false;
			private boolean find_row = false;
			private boolean find_col = false;
			private boolean find_v = false;
			private boolean is_sharedString = false;
			private int current_col_num;
			private NumberFormat current_nf = NumberFormat.General;
			private String current_value;
			private Row current_row;
			private StringBuilder sb = new StringBuilder(256);
			@Override
			public void startElement(String uri, String localName,
					String qName, Attributes attributes) throws SAXException {
				if ("v".equals(qName)) {
					if (find_col && find_row && find_sheetData)
						find_v = true;
				} else if ("c".equals(qName)) {
					if (find_row && find_sheetData) {
						find_col = true;
						//单元格缺省值
						current_value = null;
						//判断是否是共享字符串
						if ("s".equals(attributes.getValue("t")))
							is_sharedString = true;
						else is_sharedString = false;
						//获取格式索引
						String _style_id = attributes.getValue("s");
						if (_style_id != null && !_style_id.isEmpty())
							current_nf = workbook.getNumberFormats().get(
									Integer.valueOf(_style_id));
						else current_nf = NumberFormat.General;
						//获取行列值
						String _cell_index = attributes.getValue("r");
						current_col_num = getColumnIndex(_cell_index);
						//_current_row_num = getRowIndex(_cell_index);
					}
				} else if ("row".equals(qName)) {
					if (find_sheetData) {
						find_row = true;
						current_row = new Row(Integer.parseInt(attributes.getValue("r")) - 1);
						addRow(current_row);
					}
				} else if ("sheetData".equals(qName)) {
					find_sheetData = true;
				}
			}
			@Override
			public void endElement(String uri, String localName, String qName)
					throws SAXException {
				if ("v".equals(qName)) {
					if (find_v) {
						find_v = false;
						//获取字符缓冲区的内容作为单元格的值
						if (sb.length() > 0) {
							current_value = sb.toString();
							sb.delete(0, sb.length());
						}
					}
				} else if ("c".equals(qName)) {
					if (find_col) {
						find_col = false;
						//获取单元格对应的列，不存在则新建
						Column col = findColumn(current_col_num);
						if (col == null) {
							col = new Column(current_col_num);
							addColumn(col);
						}
						//如果是共享字符串，则从共享字符串中获取值作为单元格的值
						if (is_sharedString && current_value != null && !current_value.isEmpty())
							current_value = workbook.getSharedStrings().get(
									Integer.valueOf(current_value));
						//如果是时间/日期格式，则把unix格式的值转换成文本表达式
						/*
						if (_current_nf == NumberFormat.Date)
							_current_value = Utilities.convertDate(
									_current_value, workbook.getBaseYear());
						else if (_current_nf == NumberFormat.DateTime)
							_current_value = Utilities.convertDateTime(
									_current_value, workbook.getBaseYear());
						else if (_current_nf == NumberFormat.Time)
							_current_value = Utilities.convertTime(_current_value);
						*/
						//创建单元格并加入所属的列及当前行
						Cell cell = new Cell(current_value);
						cell.setColumn(col);
						cell.setRow(current_row);
						cell.setFormat(current_nf);
						col.addCell(cell);
						current_row.addCell(cell);
						//System.out.printf("cell[%d,%d] = %s\n", current_row.index, col.index, current_value);
					}
				} else if ("row".equals(qName)) {
					find_row = false;
				} else if ("sheetData".equals(qName)) {
					find_sheetData = false;
				}
			}
			@Override
			public void characters(char[] ch, int start, int length) throws SAXException {
				if (find_v && find_col && find_row && find_sheetData)
					sb.append(ch, start, length);
			}
		});
	}

	private int getColumnIndex(String name) {
		if (name == null || name.isEmpty())
			throw new RuntimeException("cell index must be not empty!");

		int number = 0;
		int pow = 1;
		for (int i = name.length() - 1; i >= 0; i--) {
			char c = name.charAt(i);
			if (c >= '0' && c <= '9')
				continue;
			number += (c - 'A' + 1) * pow;
			pow *= 26;
		}
		return number - 1;
	}

	private int getRowIndex(String name) {
		if (name == null || name.isEmpty())
			throw new RuntimeException("cell index must be not empty!");

		int number = 0;
		int pow = 1;
		for (int i = name.length() - 1; i >= 0; i--) {
			char c = name.charAt(i);
			if (c < '0' || c > '9')
				break;
			number += (c - '0') * pow;
			pow *= 10;
		}
		return number - 1;
	}

	private Column findColumn(int columnIndex) {
		return columnIndex >= columns.size() ? null : columns.get(columnIndex);
	}

	private void addColumn(Column column) {
		int max = columns.size();
		int columnIndex = column.getIndex();
		while (columnIndex >= max++) columns.add(null);
		column.setSheet(this);
		columns.set(columnIndex, column);
	}

	private void addRow(Row row) {
		int max = rows.size();
		int rowIndex = row.getIndex();
		while (rowIndex >= max++) rows.add(null);
		row.setSheet(this);
		rows.set(rowIndex, row);
	}

}
